"""
1. 函数定义语法
def 函数名(参数1, 参数2, ...) # 也可以没有参数
    函数体(函数要做的事情)
    return 返回值 # 也可以没有返回值

说明: 函数需要先定义后使用
"""
def Print(): # 函数定义
    print("hello function")

Print() # 函数调用

# 2. 函数的参数
# 要求: 给Add函数传2个参数，打印两个数相加的结果
def Add(x, y): # 形参, 按数据接收
    z = x + y
    print(z)

Add(1, 1) # 实参, 按顺序传入

# 练习: 定义一个函数，函数名随意，接收一个参数，该参数表示体温
# 要函数内进行体温判断(正常范围: 小于等于37.5度)，如果温度正常，输出温度正常，否则输出需要隔离
def judge(t):
    if t <= 37.5:
        print("温度正常")
    else:
        print("需要隔离")

judge(38)

# 3. 函数返回值
# 所谓的返回值，就是当函数执行完后，返回给调用者结果

# 案例: 计算两数之和，返回对应的结果
def add(x, y):
    return x + y
    # 注意: return 后面如果有语句是不执行的

x = add(1,2)
print(x)

# 4. 函数返回值之None类型
"""
如果函数没有使用return语句返回数据，那么其实函数默认是有返回值的
Python中有一个特殊的字面量: None，其类型是:<class 'NoneType'>
无返回值的函数，实际上就是返回了: None这个字面量

None表示: 空的、无实际意义的意思, 函数返回的None,就表示这个函数没有返回什么有意义的内容
         也就是返回空的意思
"""
def Print():
    print("hello function")
    # 不写return语句

res = Print()
print(f"返回值:{res}, 类型:{type(res)}") # 查看无返回值函数的类型和返回值

"""
None的应用场景:
1. 用在函数无返回值上
2. if判断上。在if判断中，None等同于False。一般用于函数中主动返回None。配合if判断做相关处理(常用)
3. 用于声明无内容的变量。如果变量暂时没有具体的值，可以使用None来代替
"""
def check_age(age):
    if age >= 18:
        return "success"
    else:
        return None

res = check_age(12)
if not res:
    print("未成年")
else:
    print("成年")

# 5. 函数说明文档
"""
作用: 对函数进行解释说明，帮助更好理解函数功能
语法: 在函数体前加上多行注释
"""

# 6. 函数的嵌套调用
# 意思: 一个函数中调用另一个函数
# 执行流程: 执行完调用的函数后，继续执行原函数的剩余内容
def funcc():
    print("c\n")

def funcb():
    print("b\n")
    funcc()

def funca():
    print("a\n")
    funcb()

funca()

# 七、局部变量和全局变量
# 局部变量: 定义在函数体内的变量。且作用范围在函数内部，外部无法使用
# 全局变量: 不定义在函数体内的变量。函数内部和外部均可使用
# 如果局部变量和全局变量命名冲突，局部变量优先
# 使用 global 关键字可以声明局部变量为全局变量

num = 1 # 全局变量
def chage():
    global num # 声明当前change函数的局部变量num为全局变量
    num = 100 # 此时change局部变量num就相当于全局变量，全局变量num也会被修改
    print(num)

chage()
print(num)

# 8. 函数返回多个值
# 函数如何返回多个返回值？
"""
语法:
def test_return()
    return 返回值1, 返回值2, ...

按照返回值的顺序, 写对应顺序的多个变量接收即可, 变量之间用逗号隔开
x1, x2 = test_return()
"""
def test_return():
    return "返回值是", 1

my_str, num = test_return()
print(my_str,num)

# 9. 函数多种传参方式
# 9.1 位置传参
"""
调用函数时, 根据函数定义的参数位置来传递参数。(以上学习的都是位置参数)
注意: 传递的参数和定义的参数的顺序及个数必须一致
"""
# 9.2 关键字传参
"""
函数调用时, 通过"键=值"的形式传递参数
作用: 可以让函数更加清晰、容易使用，同时也可以不按照顺序传参
"""
def user_info(name, age, gender):
    print(f"您的名字是:{name}, 年龄是:{age}, 性别是:{gender}")
# 关键字传参
user_info(name="小明",age="20", gender="男")
# 可以不按照固定顺序传参
user_info(age="20",gender="男", name="小王")
# 可以和位置传参混用，但位置参数必须在关键字参数之前, 且要匹配参数顺序
user_info("小红", gender="女", age="18")

# 9.3 缺省参数(形参)
"""
缺省参数也叫默认参数, 为函数形参提供一个默认值。
作用: 当函数调用没有传递参数, 就会默认使用缺省参数
注意: 为形参设置默认值一定要从后往前设置
"""
def user_info(name, age, gender="男"):
    print(f"您的名字是:{name}, 年龄是:{age}, 性别是:{gender}")
user_info("小太", 13)

# 9.4 不定长参数(形参)
"""
不定长参数也叫可变参数, 用于不确定调用的时候会传递多少个参数(不传参也可以)的场景
作用: 调用函数时, 不确定参数的个数时, 形参可以写成不定长参数(可变参数)
不定长参数的传入形式: 位置传递、关键字传递
"""

# 位置传递 --- 一个星号
# 传进的所有参数都会被args变量接收, args是元组类型
def user_info(*args):
    print(args)

user_info('Tom')
user_info('Tom', 18)
user_info('Tom', 18, '男')
user_info('Tom', 18, '男', '未婚')

# 关键字传递 --- 两个星号
# 参数是"键值"形式的情况下, 所有的"键值"都会被kwargs变量接收,kwarg是字典类型
def user_info(**kwargs):
    print(kwargs)
user_info(name='Tom')
user_info(name='Tom',age='18')
user_info(name='Tom',age='18',gender='男')
user_info(name='Tom',age='18',gender='男', hobby='ctrl')

# 十、匿名函数
'''
匿名函数有两种:
1. 函数作为参数传递
2. lambda匿名函数
'''
# 10.1 函数作为参数传递
def test_func(calc):
    result = calc(1, 2)
    print(f"形参的类型是:{type(calc)}")
    print(f"计算结果:{result}")

def calc(x, y):
    return x + y

test_func(calc)
# 将函数作为参数传入的作用在于: 传入的是计算逻辑, 而非传入数据

# 10.2 lambda匿名函数
"""
语法:
lambda 传入参数:函数体
1. lambda是关键字, 表示定义匿名函数
2. 传入参数表示匿名函数的形参, 如果有多个要使用逗号隔开
3. 函数体就是函数的执行逻辑, 注意: 函数的执行逻辑只能写一行, 无法写多行代码

特点:
只能使用一次
"""
def test_func(calc):
    result = calc(1, 2)
    print(f"形参的类型是:{type(calc)}")
    print(f"计算结果:{result}")

test_func(lambda x, y : x + y)